package com.moon.admin.flowable.controller;

import java.util.List;
import java.util.stream.Collectors;

import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.moon.admin.flowable.FlowableConstants.MyTaskStatusEnum;
import com.moon.admin.flowable.FlowableConstants.TaskStatusEnum;
import com.moon.admin.flowable.domain.AddSignTask;
import com.moon.admin.flowable.domain.CompleteTask;
import com.moon.admin.flowable.domain.DelegateTask;
import com.moon.admin.flowable.domain.RevokeProcessTask;
import com.moon.admin.flowable.domain.StartProcessInstance;
import com.moon.admin.flowable.domain.StopProcessInstance;
import com.moon.admin.flowable.domain.TurnTask;
import com.moon.admin.flowable.entity.ActCnHistoricProcessEntity;
import com.moon.admin.flowable.service.FlowableEngineService;
import com.moon.admin.framework.secure.AuthUtils;
import com.moon.admin.framework.secure.annotation.FormRepeat;
import com.moon.admin.framework.secure.annotation.PreAuth;
import com.moon.admin.framework.springmvc.domain.R;
import com.moon.admin.framework.syslog.annotation.SysLog;

import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * 任务管理公共组件
 * @author ninglong
 * @date 2020年1月14日
 */
@RestController
@RequestMapping("/flowable/task")
@Slf4j
public class FlowableEngineController{

	@Autowired
	private FlowableEngineService flowableEngineService;
	@Autowired
	private TaskService taskService;
	@Autowired
	private RepositoryService repositoryService;

	/**
	 * 查询 我发起的任务 列表
	 */
	@PreAuth({"flowable_unsendTask_view","flowable_sendTask_view","flowable_task_complete_view"})
	@PostMapping("myselfTaskList")
	public R<IPage<ActCnHistoricProcessEntity>> myselfTaskList(@RequestBody ActCnHistoricProcessEntity historicProcess) {
		IPage<ActCnHistoricProcessEntity> page = new Page<>(historicProcess.getPage(),historicProcess.getLimit());
		if (MyTaskStatusEnum.daifa.ordinal()==historicProcess.getStatus()) {// 待发-环节任务待办-流程未结
			page = flowableEngineService.selectMyselfProcessList(historicProcess, false, false);
		} else if (MyTaskStatusEnum.yifa.ordinal()==historicProcess.getStatus()) {// 已发-环节任务已办-流程未结
			page = flowableEngineService.selectMyselfProcessList(historicProcess, true, false);
		}
		return R.success(page);
	}
	
	/**
	 * 查询 待签、待办、已办、办结 列表
	 */
	@PreAuth({"flowable_task_unfinished_view","flowable_task_claim_view","flowable_task_finished_view","flowable_task_complete_view"})
	@PostMapping("taskList")
	public R<IPage<ActCnHistoricProcessEntity>> taskList(@RequestBody ActCnHistoricProcessEntity historicProcess) {
		IPage<ActCnHistoricProcessEntity> page = new Page<>(historicProcess.getPage(),historicProcess.getLimit());
		if (TaskStatusEnum.daiqian.ordinal()==historicProcess.getStatus()) {// 待签任务
			page = flowableEngineService.selectUnClaimProcessList(historicProcess);
		}else if (TaskStatusEnum.daiban.ordinal()==historicProcess.getStatus()) {// 待办任务
			page = flowableEngineService.selectUnfinishedProcessList(historicProcess);
		} else if (TaskStatusEnum.yiban.ordinal()==historicProcess.getStatus()) {//（已办任务）
			page = flowableEngineService.selectFinishedProcessList(historicProcess);
		}
		return R.success(page);
	}
	
	/**
	 * 查询 办结 列表
	 */
	@PreAuth("flowable_task_complete_view")
	@PostMapping("completeProcessList")
	public R<IPage<ActCnHistoricProcessEntity>> completeProcessList(@RequestBody ActCnHistoricProcessEntity historicProcess) {
		IPage<ActCnHistoricProcessEntity> page = new Page<>(historicProcess.getPage(),historicProcess.getLimit());
		if(AuthUtils.isAdministration()){// 办结任务(查看所有办结任务，一般是给管理员使用)
			page = flowableEngineService.selectCompleteProcessList(historicProcess);
		}else {// 已办结-环节任务已办-流程结束
			page = flowableEngineService.selectMyselfProcessList(historicProcess, true, true);
		}
		return R.success(page);
	}
	
	/**
	 * 发起流程(保存待发)
	 */
	@PostMapping("startProcessInstanceByDeployId")
	@SysLog(mod="任务管理",fun="发起流程")
	@FormRepeat
	@PreAuth("flowable_start_task_add")
	public R<String> startProcessInstanceByDeployId(@RequestBody StartProcessInstance startProcessInstance) {
		String processInstanceId = flowableEngineService.startProcessInstanceByDeployId(startProcessInstance.getDeployId(),startProcessInstance.getBusinessKey(),
				startProcessInstance.getProcessInstanceName(),startProcessInstance.getVariables());
		return R.success(processInstanceId);
	}
	
	/**
	 * 发起流程并提交
	 */
	@PostMapping("startProcessInstanceAndSendTaskById")
	@SysLog(mod="任务管理",fun="发起流程并提交")
	@FormRepeat
	@PreAuth("flowable_start_task_add")
	public R<String> startProcessInstanceAndSendTaskById(@RequestBody StartProcessInstance startProcessInstance) {
		String processInstanceId = flowableEngineService.startProcessInstanceAndSendTaskById(startProcessInstance.getDeployId(),startProcessInstance.getBusinessKey(),
				startProcessInstance.getProcessInstanceName(),startProcessInstance.getVariables());
		return R.success(processInstanceId);
	}
	
	/**
	 * 从待发列表中提交流程
	 */
	@GetMapping("sendFirstTask")
	@SysLog(mod="任务管理",fun="提交流程")
	@FormRepeat
	@PreAuth("flowable_unsendedTask_send")
	public R<Void> sendFirstTask(String taskId){
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		if(task==null) {
			log.warn("流程的当前任务不需要处理");
			return R.fail("任务不存在");
		}
		flowableEngineService.completeFirstTask(taskId);
		return R.success();
	}
	
	/**
	 * 签收事务
	 */
	@GetMapping("claim-task")
	@SysLog(mod="任务管理",fun="签收任务")
	@FormRepeat
	@PreAuth("flowable_task_claim_add")
	@ApiOperation(value = "签收", notes = "任务id")
	public R<Void> claimTask(String taskId) {
		taskService.claim(taskId, String.valueOf(AuthUtils.getCurrentUserId()));
		return R.success();
	}

	/**
	 * 反签收
	 */
	@GetMapping(value = "/un-claim-task")
	@SysLog(mod="任务管理",fun="反签收")
	@FormRepeat
	@PreAuth("flowable_task_claim_add")
	@ApiOperation(value = "反签收", notes = "任务id")
	public R<Void> unClaimTask(String taskId) {
		taskService.unclaim(taskId);
		return R.success();
	}

	/**
	 * 审批任务
	 */
	@PostMapping("complete-task")
	@ApiOperation(value = "审批任务", notes = "传入流程信息")
	@SysLog(mod="任务管理",fun="审批任务")
	@FormRepeat
	@PreAuth("flowable_task_unfinished_handle")
	public R<Boolean> completeTask(@RequestBody CompleteTask flow) {
		return R.status(flowableEngineService.completeTask(flow));
	}

	/**
	 * 终止
	 */
	@PostMapping(value = "/stopProcess")
	@SysLog(mod="任务管理",fun="终止流程")
	@FormRepeat
	@ApiOperation(value = "终止任务", notes = "传入流程信息")
	public R<Boolean> stopProcess(@RequestBody StopProcessInstance stopProcessInstance) {
		return R.status(flowableEngineService.stopProcessInstanceById(stopProcessInstance));
	}

	/**
	 * 撤回
	 * 
	 * 撤办任务一定是当前这个用户最近的一次完成的任务
	 */
	@PostMapping(value = "/revokeProcess")
	@SysLog(mod="任务管理",fun="撤回任务")
	@FormRepeat
	@ApiOperation(value = "撤回任务", notes = "传入流程信息")
	public R<Boolean> revokeProcess(@RequestBody RevokeProcessTask revokeProcessTask) {
		String taskId = revokeProcessTask.getTaskId();
		String processInstanceId = revokeProcessTask.getProcessInstanceId();
		//第一条是正在执行的
		List<Task> tasks = taskService.createNativeTaskQuery().sql("select * from ACT_HI_TASKINST where PROC_INST_ID_ = #{procInsId} ORDER BY START_TIME_ desc").parameter("procInsId", processInstanceId).list();
		if(tasks==null ||tasks.size()==0){
			log.error("没有查询到当前流程实例");
			return R.fail("没有查询到当前流程实例");
		}
		if(tasks.size()==1){
			log.error("当前流程还未处理，不能撤回");
			return R.fail("当前流程还未处理，不能撤回");
		}
		Task curTask = tasks.get(0);
		Task preTask = tasks.stream().filter(entity->entity.getId().equals(taskId)).collect(Collectors.toList()).get(0);
		if(curTask.getTaskDefinitionKey().equals(preTask.getTaskDefinitionKey())){
			log.error("当前流程还未处理，不能撤回");
			return R.fail("当前流程还未处理，不能撤回");
		}
        BpmnModel bpmnModel = repositoryService.getBpmnModel(preTask.getProcessDefinitionId());
		FlowNode preNode = (FlowNode)bpmnModel.getFlowElement(preTask.getTaskDefinitionKey());
		List<SequenceFlow> outs = preNode.getOutgoingFlows();
		boolean canTo = false;
		for(SequenceFlow out:outs) {
			if(curTask.getTaskDefinitionKey().equals(out.getTargetRef())) {
				canTo = true;
				break;
			}
		}
		if(!canTo) {
			log.error("当前流程已不在下级节点!");
			return R.fail("当前流程已不在下级节点!");
		}
		return R.status(flowableEngineService.revokeProcess(revokeProcessTask,preTask.getTaskDefinitionKey()));
	}
	
	/**
	 * 删除任务
	 * @param taskId 任务id
	 * @param reason 删除原因
	 */
	@GetMapping("delete-task")
	@SysLog(mod="任务管理",fun="删除任务")
	@FormRepeat
	@ApiOperation(value = "删除任务", notes = "传入删除原因")
	public R<Void> deleteTask(String taskId, String reason) {
		taskService.deleteTask(taskId, reason);
		return R.success();
	}
	
	/**
	 * 转办
	 *
	 * @param turnTask 转办参数
	 * @return
	 */
	@PostMapping(value = "/turnTask")
	@SysLog(mod="任务管理",fun="转办")
	@FormRepeat
	@ApiOperation(value = "转办任务", notes = "传入转办参数")
	public R<Boolean> turnTask(@RequestBody TurnTask turnTask) {
		return R.status(flowableEngineService.turnTask(turnTask));
	}

	/**
	 * 委派
	 * @param delegateTask 参数
	 * @return
	 */
	@PostMapping(value = "/delegateTask")
	@SysLog(mod="任务管理",fun="委派")
	@FormRepeat
	@ApiOperation(value = "委派任务", notes = "传入委派参数")
	public R<Boolean> delegateTask(@RequestBody DelegateTask delegateTask) {
		return R.status(flowableEngineService.delegateTask(delegateTask));
	}

	/**
	 * 加签
	 * @param addSignTask 加签对象
	 */
	@PostMapping("afterAddSignTask")
	@ApiOperation(value = "加签(向后)",notes = "加签")
	@SysLog(mod="任务管理",fun="加签(向后")
	@FormRepeat
	public R<Boolean> afterAddSignTask(@RequestBody AddSignTask addSignTask) {
		if(addSignTask.getSignPersoned()==null && addSignTask.getSignPersoneds()==null){
			return R.fail("请选择人员");
		}
		flowableEngineService.afterAddSignTask(addSignTask);
		return R.status(true);
	}

	/**
	 * 加签
	 * @param addSignTask 加签对象
	 */
	@PostMapping("beforeAddSignTask")
	@ApiOperation(value = "加签(向前)",notes = "加签")
	@SysLog(mod="任务管理",fun="加签(向前")
	@FormRepeat
	public R<Boolean> beforeAddSignTask(@RequestBody AddSignTask addSignTask) {
		if(addSignTask.getSignPersoned()==null && addSignTask.getSignPersoneds()==null){
			return R.fail("请选择人员");
		}
		flowableEngineService.beforeAddSignTask(addSignTask);
		return R.status(true);
	}
}